#!/usr/bin/perl -wT
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
# 
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are Copyright (C) 1998
# Netscape Communications Corporation. All Rights Reserved.
# 
# Contributor(s): TomWij <TomWij@live.com>

##############################################################################
#
# determineSeverity.cgi
# ---------------------
# Determines the severity of a bug that the user wants to submit and optionally trains the model.
#
##############################################################################

use DBI;
use DBD::mysql;
use LWP::UserAgent;
my $ua = new LWP::UserAgent;

print "Content-type: text/html\n\n";

# Load the severity map.
require severityMap;
our %toClassifier;
our %fromClassifier;

# Load the POST parameters.
do 'helpers\query.cgi';

# Check whether severities must be made for the severity.
if (not exists $toClassifier{$FORM{severity}})
{
	# If not, just return te severity the user has chosen.
	print $FORM{severity};
}
else
{
	# Allow concurrent visits.
	$current = int(rand(1000000));

	# We'll get the summary, create a test file with it and pass it to WEKA which will classify the test file against a training set, then we'll return the suggested severity.
	open (MYFILE, "data/classification");
	$classification = <MYFILE>;
	close(MYFILE);

	# Pick the right description based on what classification the user has chosen.
	$description = "";

	if ($classification eq "title")
	{
		$description = $FORM{summary};
	}
	elsif ($classification eq "content")
	{
		$description = $FORM{content};
	}
	elsif ($classification eq "both")
	{
		$description = $FORM{summary} . " " . $FORM{content};
	}

	# Write the bug to an arff file.
	open (MYFILE, ">data/test-$current.string.arff");
	$classes = "";
	foreach $key (sort(keys %fromClassifier))
	{
		$classes = $classes . $key . ',';
	}
	chop($classes);
	print MYFILE "\@relation data\n\n\@attribute short_desc string\n\@attribute bug_severity {$classes}\n\n\@data\n";
	   # Strip all non-alphanumeric characters
	   $description =~ s/[^\w\s-]//g;

	   if ($FORM{train} eq "true")
	   {
		  print MYFILE "'$description'," . $toClassifier{$FORM{severity}} . "\n";
	   }
	   else
	   {
		  print MYFILE "'$description'," . $toClassifier{'trivial'} . "\n";
	   }
	close (MYFILE);

	# We'll get the product and component id.
	do '..\..\..\localconfig';
	$driver = DBI->install_driver("mysql"); 
	$connect = $driver->connect("DBI:mysql:database=$db_name;host=$db_host", $db_user, $db_pass, {}) or print "<b>MySQL: Connection failed.</b>";

	$query = 'SELECT id FROM products WHERE name = "' . $FORM{product} . '"';
	$query_handle = $connect->prepare($query) or print "<b>MySQL: Query Preparation failed.</b>";
	$query_handle->execute() or print "<b>MySQL: Query Execution failed.</b>" . $query;
	$query_handle->bind_columns(undef, \$pid);
	$query_handle->fetch();

	$query = 'SELECT id FROM components WHERE name = "' . $FORM{component} . '" AND product_id = ' . $pid;
	$query_handle = $connect->prepare($query) or print "<b>MySQL: Query Preparation failed.</b>";
	$query_handle->execute() or print "<b>MySQL: Query Execution failed.</b>" . $query;
	$query_handle->bind_columns(undef, \$cid);
	$query_handle->fetch();

	$id = $db_name . '-' . $pid . '-' . $cid;

	# Get the classifier.
	open (MYFILE, 'data/classifier');
	$classifier = <MYFILE>;
	close(MYFILE);

	# Allow execution by de-tainting everything.
	$ENV{'PATH'} =~ /(.*)/; $ENV{'PATH'} = $1;
	$id =~ /(.*)/; $id = $1;
	$classifier =~ /(.*)/; $classifier = $1;

	unless (-e "data/$id-string.arff") {
		$ua->post('http://localhost/extensions/BugPrediction/lib/trainClassifier.cgi', { pid => $pid, cid => $cid});
	} 
	
	# Turn our bug from string format into the word vector format.
	`java -Xmx1024M -cp weka.jar weka.filters.unsupervised.attribute.StringToWordVector -S -C -R 1 -M 1 -L -c 2 -b -i data/$id-string.arff -o data/$id-vector.arff -r data/test-$current.string.arff -s data/test-$current.vector.arff`;

	# Now determine the severity or train the model using the bug.
	if ($FORM{train} eq "true")
	{
		#die "java -Xmx1024M -cp weka.jar $classifier -l data/$id-model.arff -d data/$id-model.arff -t data/test-$current.vector.arff -T data/test-$current.vector.arff > data/result-$current.arff";
		`java -Xmx1024M -cp weka.jar $classifier -l data/$id-model.arff -d data/$id-model.arff -t data/test-$current.vector.arff -T data/test-$current.vector.arff > data/result-$current.arff`;
	}
	else
	{
		`java -Xmx1024M -cp weka.jar $classifier -l data/$id-model.arff -T data/test-$current.vector.arff > data/result-$current.arff`;
	}
	unlink("data/test-$current.string.arff");
	unlink("data/test-$current.vector.arff");

	# Obtain the suggestion from the result by looking for the value behind the colon.
	open (MYFILE2, "data/result-$current.arff");
	while (<MYFILE2>) {
		if ($_ =~ m/:/)
		{
			$last = rindex($_, ':');

			$classifierResult = substr $_, $last + 1, index($_, ' ', $last) - $last - 1;
			
			print $fromClassifier{$classifierResult};
		}
	}
	close (MYFILE2);
	unlink("data/result-$current.arff");
}